/*
MIT License

Copyright (c) 2022 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo/loom
*/

#include "simodo/variable/Variable.h"

#include <cassert>

namespace simodo::variable
{
    VariableRef::VariableRef(Variable & var)
    {
        if (var.type() != ValueType::Ref)
            _variable_ptr = &var;
        else {
            VariableRef variant_ref = std::get<VariableRef>(var.variant());  // Копируем вариант со ссылкой (чуть дольше, но безопасно?)
            Variable &  ref         = variant_ref.origin();        // Получаем изменяемую ссылку

            assert(ref.type() != ValueType::Ref);
            _variable_ptr = &ref;
        }
    }

    VariableRef::VariableRef(const Variable & var_c)
    {
        Variable & var = const_cast<Variable &>(var_c);

        if (var.type() != ValueType::Ref)
            _variable_ptr = &var;
        else {
            VariableRef variant_ref = std::get<VariableRef>(var.variant());  // Копируем вариант со ссылкой (чуть дольше, но безопасно?)
            Variable &  ref         = variant_ref.origin();             // Получаем изменяемую ссылку

            assert(ref.type() != ValueType::Ref);
            _variable_ptr = &ref;
        }
    }

    VariableRef::VariableRef(Value & val)
        : _val_ptr(&val)
    {
    }

    VariableRef::VariableRef(const Value & val_c)
        : _val_ptr(const_cast<Value *>(&val_c))
    {
    }

    const Variable & VariableRef::origin() const 
    { 
        if (_val_ptr) {
            if (!_val_variable)
                _val_variable = std::make_shared<Variable>(u"", *_val_ptr);

            return *_val_variable;
        }
        return *_variable_ptr; 
    }

    Variable & VariableRef::origin()
    { 
        if (_val_ptr) {
            if (!_val_variable)
                _val_variable = std::make_shared<Variable>(u"", *_val_ptr);

            return *_val_variable;
        }
        return *_variable_ptr; 
    }

    void VariableRef::setValue(const Value & value)
    {
        if (_val_ptr) {
            *_val_ptr = value;
            if (_val_variable)
                _val_variable->value() = value;
        }
        else
            _variable_ptr->value() = value;
    }

}